﻿#include "WaveformPanel.h"

wxDEFINE_EVENT(WAVE_EVENT_CLEAR_DATA, wxCommandEvent);

wxDEFINE_EVENT(WAVE_EVENT_NEW_PLOT_DATA, WaveEventNewPlotData);

wxIMPLEMENT_DYNAMIC_CLASS(WaveformPanel, wxPlot);

WaveformPanel::WaveformPanel() : WaveformPanel(nullptr) {}

WaveformPanel::WaveformPanel(wxWindow* parent)
    : wxPlot(parent, WXPLOT_FIGURE_2D, WXPLOT_TYPE_LINE)
{
	setFontSize(10);
	setYlabel(L"LED亮度(％)");
	setXlabel(L"时间(秒)");
	gridOn(true);

	setData(std::vector<std::vector<double>>{});
	setPlotLimit(0, 8, 0, 100);
	setTicks(9, 5);

	Bind(wxEVT_SIZE, &WaveformPanel::OnSize, this);
	Bind(WAVE_EVENT_CLEAR_DATA, &WaveformPanel::OnClearData, this);
	Bind(WAVE_EVENT_NEW_PLOT_DATA, &WaveformPanel::OnNewPlotData, this);
}

void WaveformPanel::AsyncClearData() {
	GetEventHandler()->QueueEvent(
		new wxCommandEvent(WAVE_EVENT_CLEAR_DATA, GetId())
	);
}

void WaveformPanel::AsyncPushData(int tag, double x, double y) {
	GetEventHandler()->QueueEvent(new WaveEventNewPlotData(tag, x, y));
}

void WaveformPanel::OnClearData(wxCommandEvent& event) {
	event.Skip();
	waveBuffers.clear();
	setData(std::vector<std::vector<double>>{});
	setPlotLimit(0, 8, 0, 100);
	Refresh();
}

void WaveformPanel::OnNewPlotData(WaveEventNewPlotData& event) {
	event.Skip();
	auto wd = event.GetWaveData();
	auto tag = wd.tag;
	if (tag < 0 || tag >= 10) {
		return;
	}
	if (!waveBuffers.count(tag)) {
		waveBuffers[tag] = std::make_unique<boost::circular_buffer<WaveData>>(3000);
	}
	waveBuffers[tag]->push_back(wd);
	
	const double xRange = 8;
	double xMin = 0, xMax = xMin + xRange;
	if (wd.x > xMax) {
		xMax = wd.x + 0.00001;
		xMin = xMax - xRange - 0.00001;
	}
	
	std::vector<std::vector<double>> plotData;
	for (const auto& [tag, wave] : waveBuffers) {
		int cnt = 0;
		double xLast = wave->rbegin()->x;
		for (auto it = wave->rbegin(); it != wave->rend(); ++it) {
			auto x = it->x;
			if (x < xMin || x > xLast) {
				break;
			}
			xLast = x;
			cnt++;
		}

		std::vector<double> plotX, plotY;
		plotX.reserve(cnt);
		plotY.reserve(cnt);
		for (auto i = wave->size() - cnt; i < wave->size(); ++i) {
			plotX.push_back(wave->at(i).x);
			plotY.push_back(wave->at(i).y);
		}
		plotData.emplace_back(std::move(plotX));
		plotData.emplace_back(std::move(plotY));
	}

	setData(plotData);
	setPlotLimit(xMin, xMax, 0, 100);
	Refresh();
}

void WaveformPanel::OnSize(wxSizeEvent& event) {
    // If we don't use this, then refresh won't work
    event.Skip();

    // Get window size
    wxCoord startWidth = 0, startHeight = 0, endWidth, endHeight;
    GetClientSize(&endWidth, &endHeight);

    // Redraw figure
    setPlotStartWidth(startWidth);
    setPlotStartHeight(startHeight);
    setPlotEndWidth(endWidth);
    setPlotEndHeight(endHeight);
    Refresh();
}